package com.aaron.nettystudy.coding;

import com.aaron.nettystudy.serialize.Serializer;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName KyroEncoder
 * @description: 编码，使用序列化技术（将对象转换为字节数组），结果遭ByteBuf中
 * @author: 荣燊
 * @create: 2021-05-14 22:26
 **/
//自定义编码器，将消息转化为字节数组（序列化），写入到字节数据的容器ByteBuf对象中
@AllArgsConstructor
@Slf4j
//MessageToByteEncoder继承的是ChannelOutboundHandlerAdapter，出站。那么必须实现encode方法了，编码器将对象转化为字节数组
public class KyroEncoder extends MessageToByteEncoder<Object> {
    private final Serializer serializer; //参数一，传入序列化和反序列化接口
    /**
     * Class<Integer> cla;与Class<?> cl;
     * 前一个表示cla只能指向Integer这种类型，而后一个cl表示可以指向任意类型。
     *
     * cla = Integer.class 可以，但cla = Double.class就不可以。
     * 但是cl = Integer.class 可以，cl = Double.class也可以 、
     *
     * ?是通配符。
     */
    private final Class<?> genericClass; //参数二，genericClass可以指向任意类型

    //出站，要实现编码器，将对象转化为字节数组
    //encode()方法的第二个参数Object o是哪来的？
    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, Object o, ByteBuf byteBuf) throws Exception {
        if (genericClass.isInstance(o)) { //class.inInstance(obj)，判断对象o能不能被转换为genericClass类
            byte[] body = serializer.serialize(o); //序列化对象o,转换为字节数组
            int length = body.length;

            byteBuf.writeInt(length);//头部格式，四字节，表示传输的数据的字节数组大小
            byteBuf.writeBytes(body);
            log.info("编码成功~");
        }
    }
}
